using System;
using NUnit.Framework;

namespace ValidationFramework.Tests
{
    public class CustomRuleTest
    {

        const string expectedValidationMethod = "ValidateValid";
        const string expectedRuleInterpretation = "expectedRuleInterpretation";
        const string expectedRuleErrorMessage = "expectedRuleErrorMessage";
        const string expectedMethodErrorMessage = "expectedMethodErrorMessage";
        const string expectedRuleSet = "EXPECTEDRULESET";

		[TestFixture]
		public class Contruction
		{
			[Test]
			public void Simple1()
			{
                var rule = new CustomRule(typeof(ValidationClass), expectedValidationMethod, expectedRuleInterpretation);

				Assert.AreEqual(typeof(ValidationClass).GetMethod("ValidateValid"), rule.Handler.Method);
				Assert.AreEqual(expectedRuleInterpretation, rule.RuleInterpretation);
			}


			[Test]
			[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: validationType")]
			public void ExceptionTypeNameNull()
			{
				new CustomRule(null, expectedValidationMethod, expectedRuleInterpretation);
			}




			[Test]
			[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: validationMethod")]
			public void ExceptionMethodNull()
			{
                new CustomRule(typeof(ValidationClass), null, expectedRuleInterpretation);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException), ExpectedMessage = "String cannot be empty.\r\nParameter name: validationMethod")]
			public void ExceptionMethodEmpty()
			{
                new CustomRule(typeof(ValidationClass), string.Empty, expectedRuleInterpretation);
			}


			[Test]
			[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationNull()
			{
                new CustomRule(typeof(ValidationClass), expectedValidationMethod, null);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException), ExpectedMessage = "String cannot be empty.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationEmpty()
			{
                new CustomRule(typeof(ValidationClass), expectedValidationMethod, string.Empty);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException), ExpectedMessage = "CustomRule could not load the validation method 'ValidateValid2' from type 'ValidationFramework.Tests.CustomRuleTest+ValidationClass'.\r\nParameter name: validationMethod")]
			public void ExceptionMethodException()
			{
                new CustomRule(typeof(ValidationClass), "ValidateValid2", expectedRuleInterpretation);
			}


			[Test]
			public void Constructor2()
			{
				var rule = new CustomRule(ValidationClass.ValidateValid, expectedRuleInterpretation);
				Assert.AreEqual(typeof(ValidationClass).GetMethod("ValidateValid"), rule.Handler.Method);
				Assert.AreEqual(expectedRuleInterpretation, rule.RuleInterpretation);
			}


			[Test]
			[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationNull2()
			{
				new CustomRule(ValidationClass.ValidateValid, null);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException), ExpectedMessage = "String cannot be empty.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationEmpty2()
			{
				new CustomRule(ValidationClass.ValidateValid, string.Empty);
			}


			[Test]
			public void Constructor3()
			{
                var rule = new CustomRule(typeof(ValidationClass), expectedValidationMethod, expectedRuleInterpretation);
				Assert.AreEqual(typeof(ValidationClass).GetMethod("ValidateValid"), rule.Handler.Method);
				Assert.AreEqual(expectedRuleInterpretation, rule.RuleInterpretation);
			}


			[Test]
			[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationNull3()
			{
                new CustomRule(typeof(ValidationClass), expectedValidationMethod, null);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException), ExpectedMessage = "String cannot be empty.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationEmpt3y()
			{
                new CustomRule(typeof(ValidationClass), expectedValidationMethod, string.Empty);
			}


			[Test]
			public void Simple4()
			{
                var rule = new CustomRule(typeof(ValidationClass), expectedValidationMethod, expectedRuleInterpretation);
				Assert.AreEqual(typeof(ValidationClass).GetMethod("ValidateValid"), rule.Handler.Method);
				Assert.AreEqual(expectedRuleInterpretation, rule.RuleInterpretation);
				Assert.IsNull(rule.ErrorMessage);
			}


			[Test]
			[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationNull4()
			{
                new CustomRule(typeof(ValidationClass), expectedValidationMethod, null);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException), ExpectedMessage = "String cannot be empty.\r\nParameter name: ruleInterpretation")]
			public void ExceptionRuleInterpretationEmpty4()
			{
                new CustomRule(typeof(ValidationClass), expectedValidationMethod, string.Empty);
			}
		}

		[TestFixture]
		public class IsEquivalent
		{

			[Test]
			public void Simple()
			{
                var rule1 = new CustomRule(typeof(ValidationClass), "ValidateValid", expectedRuleInterpretation);
                var rule2 = new CustomRule(typeof(ValidationClass), "ValidateValid", expectedRuleInterpretation);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

                rule1 = new CustomRule(typeof(ValidationClass), "ValidateValid", expectedRuleInterpretation);
                rule2 = new CustomRule(typeof(ValidationClass), "ValidateInValidNoErrorMessage", expectedRuleInterpretation);
				Assert.IsFalse(rule1.IsEquivalent(rule2));

                rule1 = new CustomRule(typeof(ValidationClass), "ValidateValid", expectedRuleInterpretation);
                rule2 = new CustomRule(typeof(ValidationClass2), "ValidateValid", expectedRuleInterpretation);
				Assert.IsFalse(rule1.IsEquivalent(rule2));

			}
		}

		[TestFixture]
		public class Validate
		{

			[Test]
			public void Simple()
			{
                var rule = new CustomRule(typeof(ValidationClass), "ValidateValid", expectedRuleInterpretation);
				Assert.IsNull(rule.BaseValidate(null, new ValidationClass(), null, null));
			}


			[Test]
			public void InValid()
			{
                var rule = new CustomRule(typeof(ValidationClass), "ValidateInValidNoErrorMessage", expectedRuleInterpretation);
                var result = rule.BaseValidate(null, new ValidationClass(), null, null);
				Assert.IsNotNull(result);
			}


		}

		[TestFixture]
		public class GetComputedErrorMessage
		{
			[Test]
			public void Simple()
			{
			    var rule = new CustomRule(typeof (ValidationClass), "ValidateInValidWithErrorMessage", expectedRuleInterpretation);
                rule.SetDefaultErrorMessage(new MockInfoDescriptor(typeof(object).TypeHandle, "foo"));
			    Assert.IsFalse(string.IsNullOrEmpty(rule.ErrorMessage));
			}
		}


        #region class Foo (for testing)

        public class ValidationClass
        {


			public static void ValidateValid(object sender, CustomValidationEventArgs e)
            {
                var validationClass = (ValidationClass)e.TargetObjectValue;
                e.IsValid = true;
            }


			public static void ValidateInValidNoErrorMessage(object sender, CustomValidationEventArgs e)
            {
                var validationClass = (ValidationClass)e.TargetObjectValue;
                e.IsValid = false;
            }


			public static void ValidateInValidWithErrorMessage(object sender, CustomValidationEventArgs e)
            {
                var validationClass = (ValidationClass)e.TargetObjectValue;
                e.IsValid = false;
                e.ErrorMessage = expectedMethodErrorMessage;
            }
        }


        public class ValidationClass2
        {

			public static void ValidateValid(object sender, CustomValidationEventArgs e)
            {
                var validationClass = (ValidationClass)e.TargetObjectValue;
                e.IsValid = true;
            }


			public static void ValidateInValidNoErrorMessage(object sender, CustomValidationEventArgs e)
            {
                var validationClass = (ValidationClass)e.TargetObjectValue;
                e.IsValid = false;
            }


            public static void ValidateInValidWithErrorMessage(object sender, CustomValidationEventArgs e)
            {
                var validationClass = (ValidationClass)e.TargetObjectValue;
                e.IsValid = false;
                e.ErrorMessage = expectedMethodErrorMessage;
            }
        }

        #endregion
    }
}